real_os_time = real_os_time or os.time
local Timer
function os.time(tb)
    if tb then
        return real_os_time(tb)
    end
    local t = (Timer or require("core.Timer")).now
    return 0 < t and (t - t % 1000) / 1000 or real_os_time()
end


real_os_date = real_os_date or os.date
local tb = {}
for i = 1, 64 do
    tb[i] = {}
end
local tblen = 0
function os.date(fmt, t)
    t = t or os.time()
    if fmt == "*t" then
        tblen = tblen + 1
        if #tb < tblen then
            tblen = 1
        end
        local d = tb[tblen]
        d.year, d.month, d.day, d.hour, d.min, d.sec, d.wday,d.yday = global.date(t)
        return d
    else
        return real_os_date(fmt, t)
    end
end


function _G.gen_oid()
    return _G.lua_mongo.id()
end

adj = adj or {}
envs = envs or {}
file_last_modify_time = file_last_modify_time or {}
loaded = loaded or {}
str2filename = str2filename or {}
local sta = {}
tb_loadfile = tb_loadfile or {}

local function hot_dfs(a)
    if loaded[a] then
        print("hot----", a)
        loaded[a] = nil
        for b in pairs(adj[a]) do
            hot_dfs(b)
        end
    end
end

local function hot()
    for k, v in pairs(str2filename) do
        local a = global.get_file_last_modify_time(v)
        if a ~= file_last_modify_time[k] then
            file_last_modify_time[k] = a
            tb_loadfile[k] = nil
            hot_dfs(k)
        end
    end
end

collectgarbage("step", 100000)
hot()
collectgarbage("step", 100000)

local path = {
    "script/",
    "script/module/",
}

_G['is_world'] = true
local require_cnt = 0

_G.old_require =  _G.old_require or require

function require(str, not_need_exist)
    require_cnt = require_cnt + 1
    adj[str] = adj[str] or {}
    if sta[#sta] then
        adj[str][sta[#sta]] = true
    end
    sta[#sta + 1] = str
    if not loaded[str] then
        loaded[str] = true
        envs[str] = envs[str] or {
            _G = _G,
            assert = assert,
            error = error,
            ipairs = ipairs,
            load = load,
            next = next,
            pairs = pairs,
            pcall = pcall,
            print = print,
            require = require,
            setmetatable = setmetatable,
            tonumber = tonumber,
            tostring = tostring,
            type = type,

            debug = debug,
            io = io,
            math = math,
            string = string,
            table = table,
            os = os,
        }
        envs[str]._ENV = envs[str]
        if not str2filename[str] then
            local filename = string.gsub(str, "%.", "/") .. ".lua"
            local ac
            for _, v in ipairs(path) do
                local pre_filename = v .. filename
                local a = global.get_file_last_modify_time(pre_filename)
                if a ~= 0 then
                    str2filename[str] = pre_filename
                    file_last_modify_time[str] = a
                    ac = true
                    break
                end
            end
            if not ac then
                if not_need_exist then
                    return
                else
                    assert(nil, str .. " not exist")
                end
            end
        end
        local fun = tb_loadfile[str]
        if not fun then
            local err

            fun, err = loadfile(str2filename[str], nil, envs[str])

            if not fun then
                assert(nil, err)
            end
        end
        local require_cnt_old = require_cnt
        fun()
        if require_cnt_old < require_cnt then
            tb_loadfile[str] = fun
        end
    end
    sta[#sta] = nil
    return envs[str]
end

local function cmd2str(cmd)
    local f = io.popen(cmd)
    local str = f:read("*a")
    assert(io.close(f))
    return str
end

local function get_modules(str)
    local tb = {}
    local i = 1
    while true do
        local j = string.find(str, "\n", i)
        if not j then
            break
        end
        tb[#tb + 1] = string.sub(str, i, j - 1)
        i = j + 1
    end
    return tb
end
local cmd = os.getenv("OS") == "Windows_NT" and "dir/b script\\module" or "ls script/module"
local m = get_modules(cmd2str(cmd))
local Msg = require("core.Msg")

function init_proto_id()
    if has_init_proto_id then
        return
    end
    local protoIDS = require("common.ProtoID")
    has_init_proto_id = true
    Msg.proto_id = {}

    for k,v in pairs(protoIDS) do
        if type(k) == "number" then
            Msg.proto_id[v] = k
        end
    end
end
init_proto_id()

require("role.DelRoles")
local Config = require("Config")
local Filter = require("middle.Filter")
local function requireModule(module_name)
    local proto = require(module_name .. ".Proto", true)
    if not proto then
        return
    end
    local handler = require(module_name .. ".HandlerW", true)
    for k, v in pairs(proto) do
        local sub = string.sub(k, 1, 2)
        local pid = Msg.proto_id[k]
        if sub == "CG" or sub == "GC" or sub == "WL" or sub == "LW" or sub == "LL" then
            if (sub == "LW" or (sub == "CG" and pid >= Config.MIN_WORLD_CG_PROT)) and not handler[k] then
                assert(nil, k .. " not exist in handlerW.lua")
            end
            Msg.register(k, pid, v, handler and handler[k])
        end
        if sub == "CG" or sub == "LW" or sub == "WL" then
            Filter.checkBlack(module_name, pid)
        end        
    end
end

for _, v in pairs(m) do
    requireModule(v)
end

require("common.DB")
require("core.PKLimit")
local ServerCommonFW = require("serverCommon.ServerCommonFW")
local Human = require("core.Human")
local Timer = require("core.Timer")
local Monitor = require("core.Monitor")
local AdminLogic = require("admin.AdminLogic")
local MiddleLogic = require("middle.MiddleLogic")

function handlerMsg(fd, protoId)
    --print("from client W msg id ", protoId)
    local container = Msg.cg[protoId]
    if msg_ex.read(protoId, container) then
        print("err World handlerMsg msg_ex.read", protoId, Msg.proto_name[protoId])
        local mm = Msg.gc.GC_DISCONNECT
        mm.code = 0
        mm.msg = "协议读取失败"
        Msg.send(mm, fd)
        return
    end
    local human = Human.fds[fd]
    if human then
        if protoId == Msg.proto_id.CG_ASK_LOGIN then
            assert()
        end
        Monitor.handlePacket(human, container, protoId)
    else
        if protoId ~= Msg.proto_id.CG_AA_DISCONNECT and protoId ~= Msg.proto_id.CG_ASK_LOGIN then
            --如果登录了两个相同的帐号，第二个帐号把第一个帐号踢掉后，第一个帐号在收到断开的消息之前，可能继续发包，就会跑到这里来
            return
        end
        Monitor.handlePacket(fd, container, protoId)
    end
end

Timer.now = global.get_msec()	--当前时间
function handlerTime(msec)
    Timer.handlerTime(msec)
end



function handlerWorld(uuid, proto_id, dst_logic) --处理logic 发来的消息
    if dst_logic ~= -1 then
        print(" proto_id:", proto_id, uuid)        
        if not Human.onlineUuid[uuid] then
            return 0
        end
        return 1   --可以转发到其它逻辑线程
    end
    local container = Msg.lw[proto_id]
    if msg_ex.read_inner(proto_id, container) then
        print("err handlerWorld msg_ex.read", proto_id, Msg.proto_name[proto_id])
        assert()
        return 0
    end
    if proto_id == Msg.proto_id.LW_AA_DISCONNECT then
        Monitor.handlePacket(uuid, container, proto_id)
    else
        local human = Human.onlineUuid[uuid]
        if uuid ~= "" and not human then
            return 0
        elseif uuid == "" then
            human = uuid
        end
        Monitor.handlePacket(human, container, proto_id)
    end
    return 0
end


function handlerAdmin(input)
    return AdminLogic.handleAdminRequest(input)
end

function handlerMiddle(fd)
	MiddleLogic.handle(fd)
end

-- 启动之后需要做的事情，没有直接写在某个模块的init里面的原因是因为这些init需要启动初始化完完整数据之后才能进行
local function initAfterStart() --启动数据库操作，都写在这里面
    if has_init then return end
    has_init = true
    math.randomseed(os.time()*1000)
    ServerCommonFW.onInit()
    require("role.RoleFFI").init()    --初始ffi结构
    require("role.RoleDBLogic").roleDBInit() --初始化DB
    require("monster.MonsterAttrW").init()
    require("copy.CopyW").init()
    require("task.TaskGroupW").initTaskPool()
    require("family.FamilyManager").init()  
    require("mail.MailLogicFW").initAfterStart()
    require("market.HandlerW").db_init()
    require("rank.HandlerW").getRank()  
    require("admin.PayLogicW").init()
    collectgarbage("collect")  -- gc 一把
    require("activity.OpenServerActFW").onInit()
    require("activity.OpenServerActFW").onActCheck()
    require("activity.OperateActFW").onInitTodayAct()
    require("activity.OperateActFW").onActCheck()
    require("activity.ComplexSrvActFW").onInitTodayAct()
    require("activity.ComplexSrvActFW").onActCheck()
    require("activity.DateActFW").onInitTodayAct()
    require("activity.DateActFW").onActCheck()
    require("wildboss.WildBossLogicW").onActCheck()
    require("shop.HandlerW").init()
    require("offlinepk.OfflinePkLogicW").init()
    require("admin.AdminBroadcast").Init()
    require("middle.MiddleFamilySign").init()
end

local function initAfterHot()
	ServerCommonFW.VERSION_TIME_LOCAL = nil
	require("fuli.ExchangeLogic").init()
	require("rank.HandlerW").hotRank()
end


initAfterStart()
initAfterHot()

collectgarbage("collect")
print("world:"..collectgarbage("count"))

